import { useState, useEffect, useCallback } from 'react';
import { ethers } from 'ethers';
import toast from 'react-hot-toast';
import { useAuthStore } from '@/store/auth';
import { useChain } from '@/context/ChainContext';

declare global {
  interface Window {
    ethereum?: any;
  }
}

interface Web3State {
  provider: ethers.BrowserProvider | null;
  signer: ethers.JsonRpcSigner | null;
  account: string | null;
  chainId: number | null;
  isConnected: boolean;
  isConnecting: boolean;
}

export function useWeb3() {
  const { getAdminForChain } = useAuthStore();
  const { currentChain, chainConfig } = useChain();
  
  const admin = getAdminForChain(currentChain);
  const [state, setState] = useState<Web3State>({
    provider: null,
    signer: null,
    account: null,
    chainId: null,
    isConnected: false,
    isConnecting: false,
  });

  const connect = useCallback(async () => {
    console.log('Connect function called');
    console.log('window.ethereum:', window.ethereum);
    console.log('typeof window.ethereum:', typeof window.ethereum);
    
    if (!window.ethereum) {
      console.error('No window.ethereum found');
      toast.error('Please install MetaMask or another Web3 wallet');
      return false;
    }

    if (!window.ethereum.request) {
      console.error('window.ethereum.request is not a function');
      toast.error('Invalid Web3 provider. Please check your wallet extension.');
      return false;
    }

    setState(prev => ({ ...prev, isConnecting: true }));

    try {
      console.log('Requesting eth_requestAccounts...');
      console.log('window.ethereum.request type:', typeof window.ethereum.request);
      
      // Request account access
      let accounts;
      try {
        accounts = await window.ethereum.request({ method: 'eth_requestAccounts' });
      } catch (requestError) {
        console.error('Error calling eth_requestAccounts:', requestError);
        throw requestError;
      }
      
      console.log('Accounts received:', accounts);
      
      const provider = new ethers.BrowserProvider(window.ethereum);
      const signer = await provider.getSigner();
      const account = await signer.getAddress();
      const network = await provider.getNetwork();
      
      // No wallet restrictions - any wallet can connect to view their vesting data
      // Admin wallet checks are done at the function level (e.g., for claiming)
      
      setState({
        provider,
        signer,
        account,
        chainId: Number(network.chainId),
        isConnected: true,
        isConnecting: false,
      });

      return true;
    } catch (error: any) {
      console.error('Failed to connect wallet - Full error:', error);
      console.error('Error type:', typeof error);
      console.error('Error code:', error?.code);
      console.error('Error message:', error?.message);
      console.error('Error stack:', error?.stack);
      
      // Handle specific error codes
      if (error?.code === 4001) {
        // User rejected the request
        toast.error('Wallet connection cancelled');
      } else if (error?.code === -32002) {
        // Request already pending
        toast.error('Please check your wallet for pending requests');
      } else if (!error || typeof error !== 'object') {
        // Handle non-standard errors
        toast.error('Failed to connect wallet: Unknown error');
      } else {
        // Other errors
        toast.error('Failed to connect wallet: ' + (error.message || 'Unknown error'));
      }
      
      setState(prev => ({ 
        ...prev, 
        isConnecting: false,
        isConnected: false 
      }));
      
      return false;
    }
  }, [admin]);

  const disconnect = useCallback(() => {
    setState({
      provider: null,
      signer: null,
      account: null,
      chainId: null,
      isConnected: false,
      isConnecting: false,
    });
  }, []);

  const switchNetwork = useCallback(async (targetChainId: number) => {
    if (!window.ethereum) return false;

    try {
      await window.ethereum.request({
        method: 'wallet_switchEthereumChain',
        params: [{ chainId: ethers.toBeHex(targetChainId) }],
      });
      return true;
    } catch (error: any) {
      console.error('Failed to switch network:', error);
      
      // If the network doesn't exist, try to add it (for BSC testnet)
      if (error.code === 4902 && targetChainId === 97) {
        try {
          await window.ethereum.request({
            method: 'wallet_addEthereumChain',
            params: [{
              chainId: ethers.toBeHex(97),
              chainName: 'BSC Testnet',
              nativeCurrency: {
                name: 'BNB',
                symbol: 'BNB',
                decimals: 18,
              },
              rpcUrls: ['https://data-seed-prebsc-1-s1.binance.org:8545/'],
              blockExplorerUrls: ['https://testnet.bscscan.com/'],
            }],
          });
          return true;
        } catch (addError) {
          console.error('Failed to add network:', addError);
          toast.error('Failed to add BSC Testnet');
          return false;
        }
      }
      
      toast.error('Failed to switch network');
      return false;
    }
  }, []);

  // Check if already connected on mount or auto-connect for logged-in users
  useEffect(() => {
    const checkConnection = async () => {
      console.log('Checking initial connection...');
      console.log('window.ethereum exists:', !!window.ethereum);
      console.log('Logged in admin:', admin?.wallet_address);
      
      if (!window.ethereum) return;

      try {
        const accounts = await window.ethereum.request({ method: 'eth_accounts' });
        console.log('Initial accounts check:', accounts);
        
        if (accounts.length > 0) {
          const provider = new ethers.BrowserProvider(window.ethereum);
          const signer = await provider.getSigner();
          const network = await provider.getNetwork();
          
          // Auto-connect any wallet - no restrictions
          setState({
            provider,
            signer,
            account: accounts[0],
            chainId: Number(network.chainId),
            isConnected: true,
            isConnecting: false,
          });
          console.log('Auto-connected wallet:', accounts[0]);
        } else if (admin?.wallet_address) {
          // No accounts connected but user is logged in - prompt to connect
          console.log('User logged in but wallet not connected, prompting...');
          // Optionally auto-trigger connection for logged-in users
          // await connect();
        }
      } catch (error) {
        console.error('Error checking wallet connection:', error);
      }
    };

    checkConnection();
  }, [admin]);

  // Listen for account and network changes
  useEffect(() => {
    if (!window.ethereum) return;

    const handleAccountsChanged = (accounts: string[]) => {
      if (accounts.length === 0) {
        disconnect();
      } else {
        setState(prev => ({ ...prev, account: accounts[0] }));
      }
    };

    const handleChainChanged = (chainId: string) => {
      setState(prev => ({ ...prev, chainId: parseInt(chainId, 16) }));
    };

    window.ethereum.on('accountsChanged', handleAccountsChanged);
    window.ethereum.on('chainChanged', handleChainChanged);

    return () => {
      if (window.ethereum.removeListener) {
        window.ethereum.removeListener('accountsChanged', handleAccountsChanged);
        window.ethereum.removeListener('chainChanged', handleChainChanged);
      }
    };
  }, [disconnect]);

  // Effect to switch network when chain context changes
  useEffect(() => {
    const checkAndSwitchNetwork = async () => {
      if (!state.isConnected || !window.ethereum) return;
      
      const targetChainId = chainConfig.chainId;
      
      if (state.chainId !== targetChainId) {
        console.log(`Chain mismatch. Current: ${state.chainId}, Target: ${targetChainId}`);
        await switchNetwork(targetChainId);
      }
    };
    
    checkAndSwitchNetwork();
  }, [currentChain, chainConfig.chainId, state.isConnected, state.chainId, switchNetwork]);

  return {
    ...state,
    connect,
    disconnect,
    switchNetwork,
  };
}